<?php

namespace App\Console\Commands;

use App\Models\MoneyCategory;
use Illuminate\Console\Command;
use App\Models\MoneyTransaction;
use App\Models\User;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

class ImportTransactionDataCommand extends Command
{
    /**
     * 命令名称及参数
     *
     * @var string
     */
    protected $signature = 'transaction:import {--user_id= : 指定用户ID} {--reset : 重置处理进度，从头开始处理} {--limit= : 每次处理的行数限制}';

    /**
     * 命令描述
     *
     * @var string
     */
    protected $description = '从transaction_data.txt文件导入记账数据，使用AI处理并存入数据库';

    /**
     * 文件路径
     *
     * @var string
     */
    protected $filePath;

    /**
     * 缓存键名
     *
     * @var string
     */
    protected $cacheKey = 'transaction_import_line';

    /**
     * 失败记录文件路径
     *
     * @var string
     */
    protected $failureFilePath;
    protected $failureFile2Path;

    /**
     * 执行命令
     */
    public function handle()
    {
        $this->filePath = storage_path('transaction_data.txt');
        $this->failureFilePath = storage_path('transaction_import_failures.txt');
        $this->failureFile2Path = storage_path('transaction_import_failures_with_error.txt');

        // 检查文件是否存在
        if (!file_exists($this->filePath)) {
            $this->error("文件不存在: {$this->filePath}");
            return 1;
        }

        // 获取用户ID
        $userId = $this->option('user_id');
        if (!$userId) {
            $this->error('请指定用户ID，例如: --user_id=1');
            return 1;
        }

        // 获取用户及其默认账本
        $user = User::find($userId);
        if (!$user) {
            $this->error("用户不存在: {$userId}");
            return 1;
        }

        $moneyBook = $user->getCurrentDefaultBook();
        if (!$moneyBook) {
            $this->error("用户 {$userId} 没有默认账本");
            return 1;
        }

        // 是否重置处理进度
        if ($this->option('reset')) {
            Cache::forget($this->cacheKey);
            $this->info('已重置处理进度，将从头开始处理');
        }

        // 获取上次处理到的行号
        $currentLine = Cache::get($this->cacheKey, 0);
//        $currentLine = 0;
        $this->info("从第 {$currentLine} 行开始处理");

        // 获取处理行数限制
        $limit = $this->option('limit') ? (int)$this->option('limit') : null;

        // 读取文件并处理
        $file = fopen($this->filePath, 'r');
        if (!$file) {
            $this->error("无法打开文件: {$this->filePath}");
            return 1;
        }

        $lineNumber = 0;
        $processedCount = 0;
        $successCount = 0;
        $failCount = 0;

        // 跳过已处理的行
        while ($lineNumber < $currentLine && !feof($file)) {
            fgets($file);
            $lineNumber++;
        }

        // 处理数据
        $this->output->progressStart($limit ?: 100);

        while (!feof($file)) {
            $line = fgets($file);
            $lineNumber++;

            if (empty(trim($line))) {
                continue; // 跳过空行
            }

            try {
                $this->info("处理第 {$lineNumber} 行: {$line}");
                $line = trim($line);
                $tmp = explode("\t", $line);
                $text = $tmp[0]."\t".($tmp[3] ?? '');

                // 使用AI处理文本
                $result = MoneyTransaction::formatSimpleTextByAi($text, $moneyBook);

                if (!$result || isset($result['res']['error'])) {
                    $this->warn("第 {$lineNumber} 行处理失败: " . ($result['res']['error'] ?? '未知错误'));
                    $failCount++;

                    // 将失败的行写入到失败记录文件
                    $this->writeFailureToFile($lineNumber, $line, ($result['res']['error'] ?? '未知错误'));

                    continue;
                }

                $data = $result['res'];
                $typeValue = $data['type'] === 'income' ? MoneyCategory::TYPE_INCOME : MoneyCategory::TYPE_EXPENSE;

                // 创建交易记录
                MoneyTransaction::create([
                    'book_id' => $moneyBook->id,
                    'user_id' => $user->id,
                    'category_id' => $data['category_id'],
                    'sub_category_id' => $data['sub_category_id'],
                    'type' => $typeValue,
                    'amount' => $tmp[1],
                    'transaction_date' => $tmp[2],
                    'description' => $data['description'] ?: ($tmp[3] ?? ''),
                    'text' => '鲨鱼记账导入：'.$line,
                ]);

                $successCount++;
                $this->info("第 {$lineNumber} 行处理成功");
            } catch (\Exception $e) {
                exception_to_string($e);
                $this->error("第 {$lineNumber} 行处理异常: {$e->getMessage()}");
                Log::error("导入记账数据异常: {$e->getMessage()}", [
                    'line' => $lineNumber,
                    'content' => $line,
                    'trace' => $e->getTraceAsString()
                ]);
                $failCount++;

                // 将失败的行写入到失败记录文件
                $this->writeFailureToFile($lineNumber, $line, $e->getMessage());
            }

            $processedCount++;
            $this->output->progressAdvance();

            // 更新处理进度
            Cache::put($this->cacheKey, $lineNumber);

            // 如果设置了限制，达到限制后退出
            if ($limit && $processedCount >= $limit) {
                $this->info("已达到处理行数限制: {$limit}");
                break;
            }
        }

        $this->output->progressFinish();
        fclose($file);

        $this->info("处理完成，共处理 {$processedCount} 行，成功 {$successCount} 行，失败 {$failCount} 行");
        $this->info("当前处理进度: 第 {$lineNumber} 行");

        if ($failCount > 0) {
            $this->info("失败记录已保存到: {$this->failureFilePath}");
        }

        return 0;
    }

    /**
     * 将失败的行写入到失败记录文件
     *
     * @param int $lineNumber 行号
     * @param string $content 行内容
     * @param string $error 错误信息
     * @return void
     */
    protected function writeFailureToFile($lineNumber, $content, $error)
    {
        file_put_contents($this->failureFile2Path, $content.PHP_EOL, FILE_APPEND);
        $timestamp = date('Y-m-d H:i:s');
        $failureContent = "[{$timestamp}] 行号: {$lineNumber}, 内容: {$content}, 错误: {$error}\n";
        file_put_contents($this->failureFilePath, $failureContent, FILE_APPEND);
    }
}
